package com.uxsino.reactorq.clientserver;

import java.util.function.Consumer;
import java.util.function.Function;

import javax.jms.JMSException;
import javax.jms.QueueConnection;

import org.apache.commons.lang3.StringUtils;

import com.uxsino.reactorq.commons.QueueFlux;
import com.uxsino.reactorq.event.Event;
import com.uxsino.reactorq.model.BatchExecResult;

public class CallProxy {

    private long millisClientTimeout = 10000; // 10s default timeout

    private QueueConnection connection;

    public CallProxy(QueueConnection connection) {
        this.connection = connection;
    }

    public <EventType extends Event, ResponseType> JMSSyncClient<EventType, ResponseType> createEventClient(
        Class<EventType> eventType, Class<ResponseType> responseType, String srcName, String destName)
        throws JMSException {
        String eventName = Event.getEventName(eventType);
        return new JMSSyncClient<EventType, ResponseType>(connection, queueName("_event_" + eventName, srcName),
            responseType);
    }

    public <EventType extends Event> JMSSyncServer<EventType> createSyncEventServer(Class<EventType> cls,
        String srcName, String destName, Function<EventType, ?> handler) throws JMSException {
        String eventName = Event.getEventName(cls);
        return new JMSSyncServer<EventType>(connection, queueName("_event_" + eventName, srcName), destName, cls,
            handler);
    }

    public <EventType extends Event> JMSSyncMultiSessionServer<EventType> createSyncEventMultiSessionServer(
        Class<EventType> cls, String srcName, String destName, Function<EventType, ?> handler, int queueNum)
        throws JMSException {
        String eventName = Event.getEventName(cls);
        return new JMSSyncMultiSessionServer<EventType>(connection, queueName("_event_" + eventName, srcName), destName,
            cls, handler, queueNum);
    }

    /**
     * get a client takes String for both arg and response
     * 
     * @param srcName
     * @param destName
     * @param argName
     * @return
     * @throws JMSException
     */
    public JMSSyncClient<String, String> createStringClient(String srcName, String destName, String argName)
        throws JMSException {
        return this.<String, String> createClient(String.class, String.class, srcName, destName, argName);
    }

    /**
     * get a client
     * 
     * @param cls
     * @param responseType
     * @param srcName
     * @param destName
     * @param argName
     * @return
     * @throws JMSException
     */
    public <ArgType, ResponseType> JMSSyncClient<ArgType, ResponseType> createClient(Class<ArgType> cls,
        Class<ResponseType> responseType, String srcName, String destName, String argName) throws JMSException {
        return new JMSSyncClient<ArgType, ResponseType>(connection, queueName(argName, srcName), responseType)
            .setTimeout(millisClientTimeout);
    }

    /**
     * get a server
     * 
     * @param cls
     * @param srcName
     * @param destName
     * @param argName
     * @param handler
     * @return
     * @throws JMSException
     */
    public <ArgType> JMSSyncServer<ArgType> createServer(Class<ArgType> cls, String srcName, String destName,
        String argName, Function<ArgType, ?> handler) throws JMSException {
        return new JMSSyncServer<ArgType>(connection, queueName(argName, srcName), destName, cls, handler);
    }

    /**
     * get a server takes String as arg
     * 
     * @param srcName
     * @param destName
     * @param argName
     * @param handler
     * @return
     * @throws JMSException
     */
    public JMSSyncServer<String> createStringServer(String srcName, String destName, String argName,
        Function<String, ?> handler) throws JMSException {
        return new JMSSyncServer<String>(connection, queueName(argName, srcName), destName, String.class, handler);
    }

    public static String queueName(String middleName, String srcName) {
        return StringUtils.defaultIfEmpty(srcName, "_") + middleName;
    }

    /**
     * set default timeout for clients created
     * 
     * @param millisTimeout
     *            timeout in milliseconds
     */
    public CallProxy setClientTimeout(long millisTimeout) {
        millisClientTimeout = millisTimeout;
        return this;
    }

    /**
     * create jms batch client
     *
     * 使用完成后请关闭连接。
     * @param eventSender
     * @param receiverId
     * @return
     * @throws JMSException
     */
    public JMSAsyncClient<BatchExecResult> createBatchClient(Consumer<Event> eventSender, String receiverId)
        throws JMSException {
        QueueFlux<BatchExecResult> queueFlux = new QueueFlux<BatchExecResult>(connection, null, BatchExecResult.class,
            receiverId);
        JMSAsyncClient<BatchExecResult> handle = new JMSAsyncClient<BatchExecResult>(queueFlux, eventSender);
        return handle;
    }

}
